#ifndef __BUFFER_H__
#define __BUFFER_H__

#include "osa_types.h"

/**
	Buffer types defines, 32K buffer is enough
*/

typedef uint16_t buf_size_t;

typedef struct buf_t
{
    buf_size_t head;		// length of data
    buf_size_t tail;
    buf_size_t capacity;	// total length of buffer

    union
    {
        uint32_t    handle;	// linkage number like a fd
        uint32_t    owner;  //
        uint32_t    param1; //
    };

    union
    {
        uint32_t    flags;	// reserved
        uint32_t    tag;
        uint32_t    param2;
    };


    uint8_t   *data;		// pointer to storing buffer
} buf_t;

buf_t *buf_init(buf_t *buf, uint8_t *mem, buf_size_t len);

//buf_t *buf_malloc(buf_size_t len);    // return NULL if malloc failed
//void buf_free(buf_t *buf);            // free buffer


buf_size_t buf_capacity(buf_t *buf);  // return the size of buffer
buf_size_t buf_size(buf_t *buf);      // return the size of data in buffer
buf_size_t buf_left(buf_t *buf);      // return the left size in buffer
buf_size_t buf_waste(buf_t *buf);     // return the waste size in buffer

uint8_t *buf_head(buf_t *buf);        // return data pointer in buffer
uint8_t *buf_tail(buf_t *buf);        // return pointer data + len

void buf_clear(buf_t *buf);  // set length, flags to zero

/**
    Put a byte into buffer

    \param buf - the operating buffer
    \param value - value to push
    \return int >= 0 current value has been pushed, < 0 error code
*/
int  buf_putc(buf_t *buf, uint8_t value);

/**
	Write bytes into buffer

    \param buf - the operating buffer
    \param value - value to write
    \param len - length of value in bytes
    \return int int >= 0 length of bytes have been write, < 0 error code
*/
int  buf_write(buf_t *buf, uint8_t *value, buf_size_t len);

/**
	Get a byte from buffer

    \param buf - the operating buffer
    \return int < 0 if no data, or the byte popped from buffer
*/
int  buf_getc(buf_t *buf);

/**
	Read bytes from buffer

    \param buf - the operating buffer
    \param value - value buffer to store the output data
    \param len - length of value buffer
    \return int the count of bytes popped, < 0 if error, = 0 if empty
*/
int  buf_read(buf_t *buf, uint8_t *value, buf_size_t len);

/**
    Push a byte back into buffer

    \param buf - the operating buffer
    \param value - value to push
    \return int > 0 current length of buffer, < 0 error code
*/
int  buf_ungetc(buf_t *buf, uint8_t value);

/**
	Resize the data length in buffer

    \param buf - the operating buffer
    \param len - new data length
    \param tail - 0 from head, 1 from end
    \return int
*/
int  buf_resize(buf_t *buf, buf_size_t len, int tail);

/**
	Remove count of data from tail

    \param buf - the operating buffer
    \param count - count of data to be removed
    \return void
*/
void buf_remove_tail(buf_t *buf, buf_size_t count);


/**
	Remove count of data from head

    \param buf - the operating buffer
    \param count - count of bytes to be removed
    \return void
*/
void buf_remove_head(buf_t *buf, buf_size_t count);


/**
	Compact buffer if possible

    \param buf - the operating buffer
    \return void
*/
void buf_compact(buf_t *buf);

/**
    Below are similar with skbuf in Linux kernel, skb_put is not included
*/
int  buf_reserve(buf_t *buf, buf_size_t len);

uint8_t *buf_put (buf_t *buf, buf_size_t len);

uint8_t *buf_push(buf_t *buf, buf_size_t len);

uint8_t *buf_pull(buf_t *buf, buf_size_t len);


#endif /* __BUFFER_H__ */

